package com.springsummer.information.green.webmvc;


import com.springsummer.information.green.annotation.RequestMapping;
import com.springsummer.information.green.beans.ApplicationContext;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

public class NormalHandlerMappingRegistry implements HandlerMappingRegistry {



    private ApplicationContext applicationContext;

    private List<String> urlMappingNames = new ArrayList<>();

    private Map<String,Object> mappingObjs = new ConcurrentHashMap<>();

    private Map<String,Method> mappingMethods = new ConcurrentHashMap<>();

    private Map<String, HandlerMethodInfo> handlerMethodMap=new ConcurrentHashMap<>();

    public NormalHandlerMappingRegistry() {
    }

    public NormalHandlerMappingRegistry(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public void registryHandler(String urlPath, HandlerMethodInfo handlerMethod){
        handlerMethodMap.put(urlPath,handlerMethod);
        urlMappingNames.add(urlPath);
        mappingObjs.put(urlPath,handlerMethod.getHandleBean());
        mappingMethods.put(urlPath,handlerMethod.getMethod());
        Logger.getGlobal().info("MappingRegistry registryHandler urlPath:"+urlPath+" HandlerMethod:"+ handlerMethod.getMethodName());
    }

    @Override
    public boolean containsHandler(String url){
        return handlerMethodMap.containsKey(url);
    }

    @Override
    public HandlerMethodInfo findHandlerMethod(String url){
        return handlerMethodMap.get(url);
    }

    //建立URL与调用方法和实例的映射关系，存储在mappingRegistry中
    @Override
    public void initMapping(String[] controllerNames) throws Exception{
        Object obj = null;
        //String[] controllerNames = this.wac.getBeanDefinitionNames();
        //扫描WAC中存放的所有bean
        for (String controllerName : controllerNames) {

            Class<?> controllerClazz = Class.forName(controllerName);
            obj = getControllerBeanObject(controllerClazz);

            Method[] methods = controllerClazz.getDeclaredMethods();
            if (methods != null) {
                //检查每一个方法声明
                for (Method method : methods) {
                    boolean isRequestMapping =
                            method.isAnnotationPresent(RequestMapping.class);
                    //如果该方法带有@RequestMapping注解,则建立映射关系
                    if (isRequestMapping) {
                        String methodName = method.getName();
                        String urlmapping = method.getAnnotation(RequestMapping.class).path();

                        //this.getUrlMappingNames().add(urlmapping);
                        //this.getMappingObjs().put(urlmapping, obj);
                        //this.getMappingMethods().put(urlmapping, method);
                        HandlerMethodInfo handlerMethod=new HandlerMethodInfo(urlmapping,obj,obj.getClass(),method,method.getReturnType(),controllerClazz.getName(),methodName);
                        this.registryHandler(urlmapping,handlerMethod);
                    }
                }
            }
        }
    }

    private Object getControllerBeanObject(Class<?> controllerClazz) throws InstantiationException, IllegalAccessException {
        Object obj=null;
        if(this.applicationContext!=null){
            String firstChar=controllerClazz.getSimpleName().substring(0,1);
            String beanName=firstChar.toLowerCase()+controllerClazz.getSimpleName().substring(1);
            obj=applicationContext.getBean(beanName);
        }else{
            obj = controllerClazz.newInstance(); //getBean
        }
        return obj;
    }

    public List<String> getUrlMappingNames() {
        return urlMappingNames;
    }

    public void setUrlMappingNames(List<String> urlMappingNames) {
        this.urlMappingNames = urlMappingNames;
    }

    public Map<String,Object> getMappingObjs() {
        return mappingObjs;
    }

    public void setMappingObjs(Map<String,Object> mappingObjs) {
        this.mappingObjs = mappingObjs;
    }

    public Map<String,Method> getMappingMethods() {
        return mappingMethods;
    }

    public void setMappingMethods(Map<String,Method> mappingMethods) {
        this.mappingMethods = mappingMethods;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

}
